package com.github.mzule.activityrouter.router;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by apple on 2016/11/5.
 */

public class IntentRouters {
    public static String KEY_RAW_URL = Routers.KEY_RAW_URL;

    static List<Mapping> mappings = new ArrayList<>();

    private static void initIfNeed() {
        if (!mappings.isEmpty()) {
            return;
        }
        // TODO
//        RouterMapping.map();
    }

    public static void syncMapping() {
        try {
            // TODO
//            RouterMapping.map();
            Class clz = Class.forName("com.github.mzule.activityrouter.router.Routers");
            Field field = clz.getDeclaredField("mappings");
            field.setAccessible(true);
            List<Mapping> mappingList = new ArrayList<>();
            mappingList = (List<Mapping>) field.get(mappingList);
            mappings = mappingList ;
        } catch (Exception e) {
            Log.e("TAG","TAG",e);
        }
    }

    static void map(String format, Class<? extends Activity> activity, ExtraTypes extraTypes) {
        mappings.add(new Mapping(format, activity, extraTypes));
    }

    static void sort() {
        // ensure that user/collection is rank icon_top over user/:userId
        // so scheme://user/collection will match user/collection not user/:userId
        Collections.sort(mappings, new Comparator<Mapping>() {
            @Override
            public int compare(Mapping lhs, Mapping rhs) {
                return lhs.getFormat().compareTo(rhs.getFormat()) * -1;
            }
        });
    }

    public static boolean open(Context context, String url) {
        return open(context, Uri.parse(url));
    }

    public static boolean open(Context context, String url, RouterCallback callback) {
        return open(context, Uri.parse(url), callback);
    }

    public static boolean open(Context context, Uri uri) {
        return open(context, uri, null,null);
    }

    public static boolean open(Context context, Uri uri, RouterCallback callback) {
        return open(context, uri, -1, callback,null);
    }

    public static boolean openForResult(Activity activity, String url, int requestCode) {
        return openForResult(activity, Uri.parse(url), requestCode);
    }

    public static boolean openForResult(Activity activity, String url, int requestCode, RouterCallback callback) {
        return openForResult(activity, Uri.parse(url), requestCode, callback);
    }

    public static boolean openForResult(Activity activity, Uri uri, int requestCode) {
        return openForResult(activity, uri, requestCode, null,null);
    }

    public static boolean openForResult(Activity activity, Uri uri, int requestCode, RouterCallback callback) {
        return open(activity, uri, requestCode, callback,null);
    }

    public static boolean open(Context context, String url,Bundle bundle) {
        return open(context, Uri.parse(url),bundle);
    }

    public static boolean open(Context context, String url, RouterCallback callback, Bundle bundle) {
        return open(context, Uri.parse(url), callback,bundle);
    }

    public static boolean open(Context context, Uri uri, Bundle bundle) {
        return open(context, uri, null,bundle);
    }

    public static boolean open(Context context, Uri uri, RouterCallback callback,Bundle bundle) {
        return open(context, uri, -1, callback,bundle);
    }

    public static boolean openForResult(Activity activity, String url, int requestCode,Bundle bundle) {
        return openForResult(activity, Uri.parse(url), requestCode,bundle);
    }

    public static boolean openForResult(Activity activity, String url, int requestCode, RouterCallback callback,Bundle bundle) {
        return openForResult(activity, Uri.parse(url), requestCode, callback,bundle);
    }

    public static boolean openForResult(Activity activity, Uri uri, int requestCode,Bundle bundle) {
        return openForResult(activity, uri, requestCode, null,bundle);
    }

    public static boolean openForResult(Activity activity, Uri uri, int requestCode, RouterCallback callback,Bundle bundle) {
        return open(activity, uri, requestCode, callback,bundle);
    }

    private static boolean open(Context context, Uri uri, int requestCode, RouterCallback callback,Bundle bundle) {
        boolean success = false;
        try {
            if (callback != null) {
                callback.beforeOpen(context, uri);
            }
            success = doOpen(context, uri, requestCode,bundle);
            if (callback != null) {
                if (success) {
                    callback.afterOpen(context, uri);
                } else {
                    callback.notFound(context, uri);
                }
            }
        } catch (Throwable e) {
            if (callback != null) {
                callback.error(context, uri, e);
            }
        }
        return success;
    }

    private static boolean doOpen(Context context, Uri uri, int requestCode, Bundle bundle) {
        initIfNeed();
        Path path = Path.create(uri);
        for (Mapping mapping : mappings) {
            if (mapping.match(path)) {
                Intent intent = new Intent(context, mapping.getActivity());
                if (bundle == null) {
                    bundle = new Bundle();
                }
                intent.putExtras(bundle);
                intent.putExtras(mapping.parseExtras(uri));
                intent.putExtra(KEY_RAW_URL, uri.toString());
                if (!(context instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

                if (requestCode >= 0) {
                    if (context instanceof Activity) {
                        ((Activity) context).startActivityForResult(intent, requestCode);
                    } else {
                        throw new RuntimeException("can not startActivityForResult context " + context);
                    }
                } else {
                    intent.putExtras(bundle);
                    context.startActivity(intent);
                }
                return true;
            }
        }
        return false;
    }
}

